/**
 *  Copyright 2009 Henning Teek, Ingo Renner
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *  http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License. 
 */
package com.googlecode.chigs.web.common.table;

import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.apache.wicket.Component;
import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
import org.apache.wicket.injection.web.InjectorHolder;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.StringResourceModel;
import org.apache.wicket.spring.injection.annot.SpringBean;

import com.googlecode.chigs.domain.DataFileContainer;
import com.googlecode.chigs.repository.ChigsFacade;

/**
 * Sammlung von diversen Spaltentpen um auf einfache Weise ein eTabelle zu erstellen.
 * Die Tabellenspalten Überschriften werden als propertyname.label in den Sprachdateien gesucht.
 * 
 * @author Ingo Renner
 * @author Henning Teek
 */
public class AjaxFallbackDefaultDataTableBuilder implements Serializable {
	private final List<ICellPopulator<?>> columns;
	private final Component component;
	private SortableDataProvider<?> dataProvider;
    private int numberOfRows = 10;
    
    /**
     * @param component die die Ajax Tabelle enrhalten soll. 
     * @return Einen neuen Builder für die Ajax Tabelle
     */
	public static AjaxFallbackDefaultDataTableBuilder getBuilder(Component component) {		
		return new AjaxFallbackDefaultDataTableBuilder(component);
	}
	
	private AjaxFallbackDefaultDataTableBuilder(Component component) {
		this.component = component;
		columns = new ArrayList<ICellPopulator<?>>();
	}

	/**
	 * Fügt eine individuelle Spalte ein
	 * @param abstractColumn
	 * @return this for chaining
	 */
	public AjaxFallbackDefaultDataTableBuilder add(AbstractColumn<Object> abstractColumn) {
		columns.add(abstractColumn);
		return this;
	}

	/**
	 * Fügt eine normale Spalte ein. 
	 * Spaltenueberschrift wird ein StringRescourceModel mit Key = property.label
	 * Inhalt ist ein PropertyModel mit dem property 
	 * @param property
	 * @return this for chaining
	 */
	public AjaxFallbackDefaultDataTableBuilder addPropertyColumn(String property) {
		return addPropertyColumn(property, false);
	}

	/**
	 * Fügt eine normale Spalte ein. 
	 * Spaltenueberschrift wird ein StringRescourceModel mit Key = property.label
	 * Inhalt ist ein PropertyModel mit dem property, bei sortable true, kann nach dem Property sortiert werden. 
	 * @param property
	 * @param sortable
	 * @return this for chaining
	 */
	public AjaxFallbackDefaultDataTableBuilder addPropertyColumn(String property, boolean sortable) {
		columns.add(createPropertyColumn(property, sortable));
		return this;
	}
	
	/**
	 * Die Datenquelle für die tabelle.
	 * @param dataProvider
	 * @return this for chaining
	 */
	public AjaxFallbackDefaultDataTableBuilder addDataProvider(SortableDataProvider<? extends Serializable> dataProvider) {
		this.dataProvider = dataProvider;
		return this;
	}
	
	/**
	 * Diese Property muß eine Liste referenzieren, diese wird als ui List gerendert.
	 * @param listProperty
	 * @param itemProperty
	 * @return this for chaining
	 */
	public AjaxFallbackDefaultDataTableBuilder addListProperty(String listProperty,	String itemProperty) {
		ICellPopulator<?> listColumn = new ListColumn<List<?>>(
					new StringResourceModel(listProperty + ".label", component, null),
					listProperty,
					itemProperty
				);
		columns.add(listColumn);
		return this;
	}

	/**
	 * Zeigt einen * an, wenn der Propertywert true ist.
	 * @param property
	 * @return this for chaining
	 */
	public AjaxFallbackDefaultDataTableBuilder addBooleanPropertyColumn( String property) {
		return addBooleanPropertyColumn(property, false);
	}

	/**
	 * Zeigt einen * an, wenn der Propertywert true ist.
	 * @param property
	 * @return this for chaining
	 */
	public AjaxFallbackDefaultDataTableBuilder addBooleanPropertyColumn( String property, boolean sortable) {
		columns.add(crateBooleanPropertyColumn(property, sortable));
		return this;
	}

	/**
	 * 
	 * @param sortable
	 * @return this for chaining
	 */
	public AjaxFallbackDefaultDataTableBuilder addFileDownloadPropertyColumn( boolean sortable) {
		columns.add(crateFileDownloadPropertyColumn(sortable));
		return this;
	}
	
	/**
	 * Wieviele Zeilen sollen dargestellt werden.
	 * @param numberOfRows
	 * @return this for chaining
	 */
	public AjaxFallbackDefaultDataTableBuilder setNumberOfRows(int numberOfRows) {
		this.numberOfRows = numberOfRows;
		return this;
	}
	
	@SuppressWarnings("unchecked")
	public Component build(String id) {
		return new AjaxFallbackDefaultDataTable(id, columns, dataProvider, numberOfRows).setOutputMarkupId(true);
	}
	
	private ICellPopulator<?> createPropertyColumn(String property, boolean sortable) {
		if (sortable) {
			return new PropertyColumn<Object>(new StringResourceModel(property + ".label", component, null), property, property);
		} else {
			return new PropertyColumn<Object>(new StringResourceModel(property + ".label", component, null), property);
		}
	}

	private ICellPopulator<?> crateBooleanPropertyColumn(final String property, boolean sortable) {
		if (sortable) {
			return new PropertyColumn<Object>(new StringResourceModel(property + ".label", component, null), property, property){
				
				@Override
				public void populateItem(Item<ICellPopulator<Object>> item, String componentId, IModel<Object> rowModel) {
					PropertyModel<Boolean> model = new PropertyModel<Boolean>(rowModel, property);
					Boolean bool = (Boolean) model.getObject();
					item.add(bool ? new Label(componentId, "<img src=\"icons/tick.png\" alt=\"\"/>").setEscapeModelStrings(false) : new Label(componentId, "<img src=\"icons/cross.png\" alt=\"\"/>").setEscapeModelStrings(false));
				}
			};
		} else {
			return new PropertyColumn<Object>(new StringResourceModel(property + ".label", component, null),property){
				@Override
				public void populateItem(Item<ICellPopulator<Object>> item, String componentId, IModel<Object> rowModel) {
					PropertyModel<Boolean> model = new PropertyModel<Boolean>(rowModel, property);
					Boolean bool = (Boolean) model.getObject();
					item.add(bool ? new Label(componentId, "<img src=\"icons/tick.png\" alt=\"\"/>").setEscapeModelStrings(false) : new Label(componentId, "<img src=\"icons/cross.png\" alt=\"\"/>").setEscapeModelStrings(false));
				}
			};
		}
	}
	
	private ICellPopulator<?> crateFileDownloadPropertyColumn(boolean sortable) {
		
		if (sortable) {
			return new PropertyColumn<Object>(new StringResourceModel("file.label", component, null), "file", "file"){
				@SpringBean
				private ChigsFacade chigs;

				@Override
				public void populateItem(Item<ICellPopulator<Object>> item, String componentId, IModel<Object> rowModel) {
					if (rowModel.getObject() instanceof DataFileContainer) {
						InjectorHolder.getInjector().inject(this);
						final String fileName = (String) new PropertyModel<String>(rowModel, "filename").getObject();;
						final String digest = (String) new PropertyModel<String>(rowModel, "hash").getObject();;
						final File file = chigs.getDataFile(digest);
						item.add(new DownloadPanel(componentId, fileName, file));
					} else {
						item.add(new Label(componentId, "Object must implement DataFileContainer: " + getSafeClassname(rowModel)));
					}
				}

			};
		} else {
			return new PropertyColumn<Object>(new StringResourceModel("file.label", component, null),"file"){
				@SpringBean
				private ChigsFacade chigs;
				
				@Override
				public void populateItem(Item<ICellPopulator<Object>> item, String componentId, IModel<Object> rowModel) {
					if (rowModel.getObject() instanceof DataFileContainer) {
						InjectorHolder.getInjector().inject(this);
						final String fileName = (String) new PropertyModel<String>(rowModel, "filename").getObject();;
						final String digest = (String) new PropertyModel<String>(rowModel, "hash").getObject();;
						final File file = chigs.getDataFile(digest);
						item.add(new DownloadPanel(componentId, fileName, file));
					} else {
						item.add(new Label(componentId, "Object must implement DataFileContainer: " + getSafeClassname(rowModel)));
					}
				}
			};
		}
	}

	private String getSafeClassname(IModel<Object> rowModel) {
		if (rowModel == null) {
			return "model is null";
		}
		return rowModel.getObject() == null ? "model object is null" : rowModel.getObject().getClass().getSimpleName();
	}
	
}
